package com.eureka.Controller;//package com.example.utilsm2.controller;

import com.eureka.server.DemoServer;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import com.netflix.eureka.resources.PeerReplicationResource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient;
import org.springframework.cloud.netflix.eureka.server.InstanceRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Aspect
@Slf4j
@RestController
public class DemoController {

    @Autowired
    private DemoServer demoServer;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private PeerAwareInstanceRegistry peerAwareInstanceRegistry;

    @Autowired
    private DemoController demoController;

    public List<String> getExcludeService(){
        return Arrays.asList("ES1");
    }

    @PostMapping("/demo")
    public String abc(@RequestParam String abc) {
        InstanceRegistry bean = applicationContext.getBean(InstanceRegistry.class);
//        bean.register(InstanceInfo);
        List<String> services = discoveryClient.getServices();

        List<InstanceInfo> allInstanceInfos = new ArrayList<>();
        for (String service : services) {
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
//            ServiceInstance serviceInstance = instances.get(0);
            List<InstanceInfo> instanceInfos = instances.stream().map(x -> mapToInstanceInfo(x)).filter(Objects::nonNull).collect(Collectors.toList());
            allInstanceInfos.addAll(instanceInfos);
            System.out.println(instances);
        }
        for (InstanceInfo oneInfo : allInstanceInfos) {
            // false会同步给其他集群，true不会
            bean.deleteStatusOverride(oneInfo.getAppName(),oneInfo.getId(), InstanceInfo.InstanceStatus.DOWN,oneInfo.getLastDirtyTimestamp().toString(),false);
            if(!demoController.getExcludeService().contains(oneInfo.getAppName().toUpperCase())){
                bean.register(oneInfo,true);
            }
        }
        return demoServer.sayHello(abc);
    }

    private InstanceInfo mapToInstanceInfo(ServiceInstance x) {
        if(x instanceof EurekaDiscoveryClient.EurekaServiceInstance){
            InstanceInfo instanceInfo = ((EurekaDiscoveryClient.EurekaServiceInstance) x).getInstanceInfo();
            return instanceInfo;
        }
        return null;
    }

    @Scheduled(cron = "0/30 * * * * ?")// 每30s执行一次
//    @Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行一次
    //或直接指定时间间隔，例如：30秒
    //@Scheduled(fixedRate=5000)
    private void syncInfo() {
        String abc = demoController.abc("123");
        System.out.println(abc);
    }

//    @Around("execution(*  org.springframework.cloud.netflix.eureka.server.InstanceRegistry.register(com.netflix.appinfo.InstanceInfo, boolean))")
    @Around("execution(* com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl.*(..))")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        if(Arrays.asList("cancel","register","renew","statusUpdate","deleteStatusOverride").contains(joinPoint.getSignature().getName())){
            // 获取原始参数
            Object[] args = joinPoint.getArgs();
            // false会同步给其他集群，true不会
            args[args.length-1] = true;
            // 设置修改后的参数并继续执行原方法
            Object result = joinPoint.proceed(args);
            return result;
        }
        return joinPoint.proceed();
    }


}